import Component from "../Component.js";
import Type from "../../experience/db/Type.js";
import Socket from "../../experience/utils/Socket.js";
import {_delay, _timeout} from "../../experience/utils/F7.js";
import { CONF } from "../../configure/Assets.js"

const Feature = ol.Feature;
const Point = ol.geom.Point;
const Text = ol.style.Text;
const Fill = ol.style.Fill;
const Stroke = ol.style.Stroke;
const Style = ol.style.Style;
const Icon = ol.style.Icon;
const LineString = ol.geom.LineString;
const Overlay = ol.Overlay;


export default class Vehicle extends Component{
    constructor() {
        super();

        this.vehicles = null;
        this.datas = new Map();
        this.THRESHOLD = 0.000001;
        this.vehicleId = this.utils.getLocalStorage("vehicleId");

        // 比例尺锁和车辆移动锁
        this.zoomlocked = true;
        this.lockedUnlocked = true;

        // 轨迹回放相关
        this.playbacks = [];
        this.playbackIndex = 0;
        this.playbackLocked = false;
        this.playbacklength = 1;
        this.playbacktimer = null;

        // 车辆被选中状态相关
        this.selectedId = null;
        this.selectedTimer = null;

        // 车速补偿相关
        this.selfinfo = null;
        this.readerid = -1;
        this.direction = 0;
        this.rdirection = -1;
        this.distance = 0.0;
        this.smaller = true;
        this.lastleft = false;
        this.lastx = 0;
        this.lasty = 0;
        this.lastangle = 0;

        // 陀螺仪角动量相关
        this.gyroAngle = 0;
        this.gyroAngles = [];
        this.gyroRange = 0.0;
        this.gyroMistake = 0;
        this.gyroTotal = 0;
        this.gyroCount = 0;

        // 设置Vehicle弹出对话框
        const container = document.getElementById("ol-vehicle-popup");
        const closer = document.getElementById("ol-vehicle-closer");
        if (container !== null && closer !== null) {
            const self = this;
            closer.onclick = function () {
                self.overlay.setPosition(undefined);
                clearInterval(self.selectedTimer);
                self.emitter.emit("cancel-selected");
                self.selectedId = null;
                closer.blur();
                return false;
            };

            this.emitter.on("close-overlay", () => {
                self.overlay.setPosition(undefined);
                clearInterval(self.selectedTimer);
                self.emitter.emit("cancel-selected");
                self.selectedId = null;
                closer.blur();
            });

            this.overlay = new Overlay({ element: container });
            this.drawer.map.addOverlay(this.overlay);
        }

        // 取配置文件信息
        const config = this.algo.getConfig();
        if (config === null) return;

        // 获取轨迹线数据
        this.tracks = new Map();
        this.api.getTracks({ meta_id: config.meta_id, type: "vehicle" }).then(t => {
            for (const data of t.data) {
                this.tracks.set(data.id, data);
            }
        });

        // 获取人员定位分站数据
        this.positions = new Map();
        this.api.getPositions({ meta_id: config.meta_id, type: "vehicle" }).then(p => {
            for (const data of p.data) {
                this.positions.set(data.node_id, data);
            }
        });

        // 获取读卡器信息
        this.readers = new Map();
        this.api.getReaders().then(r => {
            for (const data of r.data) {
                this.readers.set(data.readerid, data);
            }
        });
    }

    clear() {
        this.playbackIndex = 0;
        this.playbackLocked = false;
        this.playbacklength = 1;
        this.$$("#person-slider").val(0);
        this.$$("#vp-footer").hide();
        this.$$("#vl-vehicle-track-back").css("background", "green");
        this.$$("#vl-vehicle-track-back").html("开始回放");
        clearInterval(this.playbacktimer);
    }

    info(vehicle) {
        const regionName = vehicle.regname;
        const dir = vehicle.dir === 0 ? "前" : "后";
        const distance = vehicle.distance;
        this.$$("#ol-inminetime").html(vehicle.inminetime);
        this.$$("#ol-reader").html(`${regionName}${dir}${distance}米`);
        this.$$("#ol-speed").html(`${vehicle.speed}Km/h`);
        this.$$("#ol-mileage").html(`${vehicle.mileage}Km`);
        this.$$("#ol-wt").html(`${vehicle.water_temp}℃`);
        this.$$("#ol-ch4").html(`${vehicle.ch4_conc}%`);
        this.$$("#ol-st").html(`${vehicle.surface_temp}℃`);
        this.$$("#ol-et").html(`${vehicle.exhaust_temp}℃`);
        this.$$("#ol-rpm").html(`${vehicle.rpm}rpm`);
        this.$$("#ol-battery").html(`${vehicle.battery}%`);
        this.overlay.setPosition([vehicle.x, vehicle.y]);
    }

    draw() {
        this.drawer.source(Type.Vehicle).clear();
        if (this.utils.getLocalStorage("edit")) return;
        const mode = this.utils.getLocalStorage("mode");
        if (mode !== "vehicle") return;

        const vehicleId = this.utils.getLocalStorage("vehicleId");
        const config = this.algo.getConfig();
        let vehicle = null

        this.datas.forEach((item) => {
            if (this.vehicleId === item.carcode || vehicleId === item.carcode) {
                vehicle = item;
                return;
            }

            const feature = new Feature();
            feature.setId(item.id);
            feature.set('type', Type.Vehicle);
            feature.set('carcode', item.carcode);
            const style = new Style({
                image: new Icon({
                    src: item.type === 1 ? CONF.VEHICLE.other_bus : CONF.VEHICLE.other_ton,
                    scale: config.scale / 8,
                    rotation: -item.angle
                }),
                text: new Text({
                    text: item.name,
                    fill: new Fill({ color: 'white' }),
                    font: `normal 14px "iconfont"`,
                    textAlign: 'center',
                    textBaseline: 'middle',
                    offsetX: 0, offsetY: 30
                })
            });

            feature.setStyle(style);
            item.x = this.algo.normalX(item.x);
            item.y = this.algo.normalY(item.y);
            feature.setGeometry(new Point([item.x, item.y]));
            this.drawer.source(Type.Vehicle).addFeature(feature);
        });

        if (vehicle === null) return;

        const feature = new Feature();
        feature.setId(vehicle.id);
        feature.set('type', Type.Vehicle);
        feature.set('carcode', vehicle.carcode);

        const style = new Style({
            image: new Icon({
                src: vehicle.type === 1 ? CONF.VEHICLE.self_bus : CONF.VEHICLE.self_ton,
                scale: config.scale / 8,
                rotation: -vehicle.angle
            }),
            text: new Text({
                text: vehicle.name,
                fill: new Fill({ color: 'white' }),
                font: `normal 14px "iconfont"`,
                textAlign: 'center',
                textBaseline: 'middle',
                offsetX: 0, offsetY: 30
            })
        });

        feature.setStyle(style);
        vehicle.x = this.algo.normalX(vehicle.x);
        vehicle.y = this.algo.normalY(vehicle.y);
        feature.setGeometry(new Point([vehicle.x, vehicle.y]));
        this.drawer.source(Type.Vehicle).addFeature(feature);
    }

    vehicle(vehicles) {
        for (const vehicle of vehicles) {
            // 1.如果是终端模式
            if (this.vehicleId === vehicle.carcode) {
                // 从端口为8899的Websocket获取的数据
                if (this.selfinfo !== null) {
                    const s = this.selfinfo;

                    // 方向和车速有时候会出现空的情况,需要容错
                    if (s.speed === null || s.speed === "") s.speed = 0;
                    if (s.direction === null || s.direction === "") s.direction = this.direction;

                    console.log("|-----------------------------|");
                    console.log("[T]", moment().format('YYYY-MM-DD HH:mm:ss'));
                    console.log("[S]", s.ip4, s.direction, s.distance1, s.speed);
                    console.log("[G]", this.gyroAngles.length, this.gyroRange);

                    // 赋值其它属性
                    vehicle.speed = parseFloat(s.speed).toFixed(1);
                    vehicle.mileage = s.totalMiles ? s.totalMiles : vehicle.mileage;
                    vehicle.ch4_conc = s.ch4 ? parseInt(s.ch4) : vehicle.ch4_conc;
                    vehicle.rpm = s.rpm ? s.rpm : vehicle.rpm;
                    vehicle.battery = s.battery ? s.battery : vehicle.battery;
                    vehicle.exhaust_temp = s.exhTemp ? s.exhTemp : vehicle.exhaust_temp;
                    vehicle.surface_temp = s.engTemp ? s.engTemp : vehicle.surface_temp;
                    vehicle.water_temp = s.coolTemp ? s.coolTemp : vehicle.water_temp;

                    if (s.ip4 === 0 || Math.abs(s.distance1) < 0.001) {
                        if (this.readerid !== -1) {
                            // 千米/时 => 米/秒,保留2为小数
                            const speed = parseFloat(s.speed) / 3.6 / 1.7;

                            // 如果信号丢失了
                            if (this.smaller) {
                                // 当前为逐渐变小的情况下
                                this.distance -= speed;
                                console.log("[BS]", speed, this.distance);

                                // 逐渐减少为0的情况下
                                if (this.distance < 0) {
                                    this.distance = 0;
                                    this.smaller = false;
                                    this.direction = this.direction === 0 ? 2 : 0;
                                }
                            } else {
                                // 当前为逐渐变大的情况下
                                this.distance += speed;
                                console.log("[BD]", speed, this.distance);
                            }
                            vehicle.readerid = this.readerid;
                            vehicle.dir = parseInt(this.direction);
                            vehicle.yukirin = parseFloat(this.distance);
                        }
                    } else {
                        // 如果和上次的分站、方向、距离
                        if (this.readerid === s.ip4 &&
                            this.direction === s.direction &&
                            this.distance === s.distance1) {

                            vehicle.x = this.lastx;
                            vehicle.y = this.lasty;
                            vehicle.angle = this.lastangle;
                            this.datas.set(vehicle.id, vehicle);
                            this.$$("#speed").html(`车辆速度: ${vehicle.speed}Km/h`);
                            continue;
                        }

                        // 跳到了下一个分站,统计数据列表为空,绝对值趋势变小
                        if (this.readerid !== s.ip4) {
                            this.direction = parseInt(s.direction);
                            this.distance = parseFloat(s.distance1);
                            this.smaller =  true;

                            // 查看上一个分站的情况,通过两个分站的连线计算方向
                            const a = this.positions.get(this.readerid);
                            const b = this.positions.get(s.ip4);
                            if (a !== undefined && b !== undefined) {
                                const r = this.algo.route(a, b, this.tracks);
                                this.rdirection = r.dir ? 2 : 0;
                                console.log("[R]", this.readerid, s.ip4, r.dir, this.rdirection);
                            }
                        }

                        // 给分站编号赋值
                        this.readerid = s.ip4;

                        // 如果反方向距离太大,证明车辆已经偏航
                        if (Math.abs(s.distance1 - this.distance) > 30) {
                            this.smaller = !this.smaller;
                            this.distance = parseFloat(s.distance1);
                            this.rdirection = -1;
                            console.log("[PH]", s.distance1, this.distance);
                        } else {
                            // 逐渐变小的情况下
                            if (this.smaller) {
                                // 如果统计数据很少,我们暂定认为方向和第一条记录一致
                                let direction = this.direction;
                                if (this.rdirection !== -1) {
                                    direction = this.rdirection;
                                }

                                // 在变小模式下,如果已经十分接近分站中心点,则标记反转方向
                                if (this.distance < 10) {
                                    direction = direction === 0 ? 2 : 0;
                                    this.distance = 0;
                                    this.smaller = false;
                                }
                                this.direction = direction;

                                // 这里,后出现的距离不能不之前的大
                                this.distance = parseFloat(s.distance1) > this.distance ? this.distance : s.distance1;
                            } else {
                                // 这里,后出现的距离不能不之前的小
                                this.distance = parseFloat(s.distance1) < this.distance ? this.distance : s.distance1;
                            }
                        }
                    }

                    if (this.readerid !== -1) {
                        vehicle.readerid = this.readerid;
                        vehicle.dir = parseInt(this.direction);
                        vehicle.yukirin = parseFloat(this.distance);
                    }

                    console.log("[E]", vehicle.readerid, vehicle.dir,
                        vehicle.yukirin.toFixed(1), vehicle.speed
                    );

                    // 判断分站是否能存在,如果不存在车辆保持不动
                    const postion = this.positions.get(parseInt(vehicle.readerid));
                    if (postion === undefined) {
                        vehicle.x = this.lastx;
                        vehicle.y = this.lasty;
                        vehicle.angle = this.lastangle;
                        this.datas.set(vehicle.id, vehicle);
                        this.$$("#speed").html(`车辆速度: ${vehicle.speed}Km/h`);
                        continue;
                    }

                    // 判断轨迹线是否存在,如果不存在车辆保持不动
                    const track = this.tracks.get(postion.track_id);
                    if (track === undefined) {
                        vehicle.x = this.lastx;
                        vehicle.y = this.lasty;
                        vehicle.angle = this.lastangle;
                        this.datas.set(vehicle.id, vehicle);
                        this.$$("#speed").html(`车辆速度: ${vehicle.speed}Km/h`);
                        continue;
                    }

                    // 计算车辆位置
                    const v = this.algo.xyd100(postion, track.points, vehicle.dir, vehicle.yukirin);

                    // 如果和上次的位置相差较近
                    const d = this.algo.distance(v.x,  v.y, this.lastx,  this.lasty);
                    if (d < 1.5) {
                        vehicle.x = this.lastx;
                        vehicle.y = this.lasty;
                        vehicle.angle = this.lastangle;
                        this.datas.set(vehicle.id, vehicle);
                        this.$$("#speed").html(`车辆速度: ${vehicle.speed}Km/h`);
                        continue;
                    }

                    // 如果和上次的位置相差较远
                    vehicle.x = v.x; vehicle.y = v.y; vehicle.grid = v.grid;
                    vehicle.angle = this.algo.angle(v.grid, vehicle.dir, this.lastleft);

                    // 记录一下当前运算好的数据
                    this.lastleft = (vehicle.x < this.lastx);
                    this.lastx = vehicle.x;
                    this.lasty = vehicle.y;
                    this.lastangle = vehicle.angle;

                    this.$$("#distance").html(`相对位置: ${vehicle.yukirin.toFixed(2)}米`);
                } else {
                    this.$$("#distance").html(`相对位置: ${vehicle.distance.toFixed(2)}米`);
                }

                // 需要添加左上的状态信息
                this.$$("#vehicleid").html(`识别卡号: ${vehicle.carcode}`);
                this.$$("#readerid").html(`读卡器: ${vehicle.regname}`);
                this.$$("#direction").html(`相对方向: ${vehicle.dir === 0 ? "前" : "后"}`);
                this.$$("#speed").html(`车辆速度: ${vehicle.speed}Km/h`);

                // 将中心坐标始终指向这辆车
                const x = this.algo.normalX(vehicle.x);
                const y = this.algo.normalY(vehicle.y);
                if (this.zoomlocked) {
                    // 打开车辆追踪模式,第一次要放大地图
                    this.zoomlocked = false;
                    this.drawer.map.getView().setCenter([x, y]);
                    this.drawer.map.getView().setZoom(12);
                } else {
                    this.drawer.map.getView().animate({center: [x, y], duration: 500});
                    // this.drawer.map.getView().setCenter([x, y]);
                }
            }

            // 2.如果车辆信息对话框已经打开
            if (this.selectedId === vehicle.carcode) {
                const x = this.algo.normalX(vehicle.x);
                const y = this.algo.normalY(vehicle.y);
                this.overlay.setPosition([x, y]);
            }

            this.datas.set(vehicle.id, vehicle);
        }
    }

    async playlist() {
        this.clear();

        this.drawer.source(Type.Modify).clear();
        const stime = this.$$("#ol-stime").val();
        const etime = this.$$("#ol-etime").val();
        if (stime === "" || etime === "") {
            this.toast("您选择的时间范围存在问题。");
            return;
        }

        const carid = this.$$("#ol-carcode").html();
        const params = { carid: carid, stime: stime, etime: etime };

        if (CONF === "OnePiece") {
            this.emitter.emit("emit-vehicle-playlist", params);
            return;
        }

        const data = await this.api.trackPlayBack(params);
        if (data.length === 0) {
            this.toast("未获取到车辆轨迹数据。");
            return;
        }

        this.panel();
        this.$$("#vl-title").html("轨迹回放");
        this.$$("#vl-vehicle-track-back").show();
        this.$$("#vp-footer").show();

        this.$$("#pannel .page-content").empty();
        this.$$("#pannel").show();
        const div = `<div class="block"><div class="list simple-list"><ul></ul></div></div>`;
        this.$$("#pannel .page-content").append(div);

        this.playbacks = [];
        for (const item of data) {
            const id = `track-${this.utils.uuid()}`;
            const time = item.intime.split('T')[1], time_str = item.intime.replace('T', ' ');
            this.playbacks.push({id: id, rid: parseInt(item.rid), carid: carid, time: time_str});
            let name = item.position;
            if (name.length > 15) { name = item.position.substring(0,18) + "..."; }
            const li = `
                <li style="font-size: var(--table-row-font-size); cursor: pointer; display: flex; 
                    justify-content: space-between;" id=${id}>
                    <span>${name}</span> <span>${time}</span>
                </li>
            `;
            const color = this.$$("li").css("background-color");

            this.$$("#pannel ul").append(li);
            this.$$(`#${id}`).on("click", () => {
                _delay('vehicle-playback', async () => {
                    // 正在播放时,不允许进行点击
                    if (this.playbackLocked) {
                        this.toast("正在播放时不允许选择。");
                        return ;
                    }

                    // 首先先恢复所有颜色为默认
                    for (let i = 0; i < this.playbacks.length; i++) {
                        const item = this.playbacks[i];
                        this.$$(`#${item.id}`).css("background-color", color);
                    }

                    // 将选中的列以上的列全都设置为已处理
                    for (let i = 0; i < this.playbacks.length; i++) {
                        const item = this.playbacks[i], position = this.positions.get(item.rid);
                        if (position === undefined) {
                            this.$$(`#${item.id}`).css("background-color", "rgb(255, 255, 0, 0.8)");
                        } else {
                            this.$$(`#${item.id}`).css("background-color", "rgb(0, 255, 0, 0.8)");
                        }
                        if (id === item.id) {
                            // 记录一下开始位置
                            this.playbackIndex = i;
                            break;
                        }
                    }
                }, 300);
            });
        }
    }

    async playback(index = 0) {
        this.toast("注意: 绿色为规定轨迹线、橙色为非规定轨迹线。");

        // 添加移动的车辆
        const car = new Feature(), playbacks = this.playbacks;
        const icon = new Icon({src: CONF.VEHICLE.playback, size: [60, 60]});
        car.setStyle(new Style({image: icon}));
        this.drawer.source(Type.Modify).addFeature(car);

        // 添加轨迹线
        const db = await this.db.index(Type.Track, "type", "vehicle");
        db.forEach(item => {
            item.points.forEach(p => {
                p[0] = this.algo.normalX(p[0]); p[1] = this.algo.normalY(p[1]);
            });

            const feature = new Feature();
            feature.setStyle(new Style({stroke: new Stroke({width: 2, color: 'orange'})}));
            feature.setGeometry(new LineString(item.points));
            this.drawer.source(Type.Modify).addFeature(feature);
        });

        // 如果存在规定轨迹线,则显示出来
        const param = { car_id: playbacks[0].carid, time: playbacks[0].time };
        const data = await this.api.getCarTracks(param);
        data.data.forEach(item => {
            item.coordinates.forEach(p => {
                p[0] = this.algo.normalX(p[0]); p[1] = this.algo.normalY(p[1]);
            });

            const feature = new Feature();
            feature.setStyle(new Style({stroke: new Stroke({width: 6, color: 'green'})}));
            feature.setGeometry(new LineString(item.coordinates));
            this.drawer.source(Type.Modify).addFeature(feature);
        });

        const length = this.playbacks.length;
        let i = index, count = 0, flag = true, x1, y1, x2, y2, k, distance;
        let points = [], dl = 0;
        this.playbacktimer = setInterval(async () => {
            // 停止轨迹回放
            if (!this.playbackLocked || i === length - 1) {
                this.playbackIndex = i;
                this.drawer.source(Type.Modify).clear();
                clearInterval(this.playbacktimer);
                return;
            }

            const curr = playbacks[i], next = playbacks[i + 1];
            if (flag) {
                flag = false;

                // 如果是一张图模式,通知一下当前已经播放的位置
                if (CONF === "OnePiece") {
                    this.emitter.emit("emit-vehicle-playback-response", i);
                }

                // 判断当前分站是否存在,如果不存在标记为黄色
                this.$$(`#${curr.id}`).css("background-color", "rgb(255, 255, 0, 0.8)");
                const currPosition = this.positions.get(curr.rid);
                if (currPosition === undefined) { i = i + 1; flag = true; return; }
                this.$$(`#${curr.id}`).css("background-color", "rgb(0, 255, 0, 0.8)");

                // 判断下一个分站是否存在,如果不存在标记为黄色
                this.$$(`#${next.id}`).css("background-color", "rgb(255, 255, 0, 0.8)");
                const nextPosition = this.positions.get(next.rid);
                if (nextPosition === undefined) { i = i + 1; flag = true; return; }
                this.$$(`#${next.id}`).css("background-color", "rgb(0, 255, 0, 0.8)");

                const r = this.algo.route(currPosition, nextPosition, this.tracks);
                points = r.points;
                dl = this.algo.distances(points);
                const x = this.algo.normalX(points[0][0]), y = this.algo.normalY(points[0][1]);
                this.drawer.map.getView().animate({ center: [x, y] });
            }

            const point = this.algo.xyd10(points, count);
            const x = this.algo.normalX(point[0]), y = this.algo.normalY(point[1]);
            car.setGeometry(new Point([x, y]));
            count = count + this.playbacklength;
            if (count > dl) {
                flag = true; count = 0; i = i + 1;
            }
        }, 100);
    }

    // gyroscope(x) {
    //     // 陀螺仪满足误差的前提下,对角动量进行积分
    //     if (this.gyroCount > 10000) {
    //         // 陀螺仪满足误差的前提下,对角动量进行积分
    //         const dx = x - this.gyroMistake;
    //         this.gyroAngle += dx
    //         this.gyroAngles.push(this.gyroAngle);
    //
    //         // 保留500个角度值,大于500个删除最开始的值
    //         if (this.gyroAngles.length > 500) {
    //             this.gyroAngles.shift();
    //             const max = Math.max(...this.gyroAngles);
    //             const min = Math.min(...this.gyroAngles);
    //             this.gyroRange = Math.abs(max - min);
    //         }
    //     } else {
    //         // 这里得先统计一下陀螺仪的误差
    //         this.gyroTotal += x;
    //         this.gyroCount += 1;
    //         this.gyroMistake = this.gyroTotal / this.gyroCount;
    //     }
    // }

    positionById(id) {
        const position = this.positions.get(id);
        const text = new Text({
            text: '\ue651',
            fill: new Fill({ color: 'red' }),
            font: `normal 30px "iconfont"`
        });

        const x = this.algo.normalX(position.x);
        const y = this.algo.normalY(position.y);
        const feature = new Feature();
        feature.setStyle(new Style({ text: text }));
        feature.setGeometry(new Point([x, y]));
        this.drawer.source(Type.Modify).addFeature(feature);
        this.drawer.map.getView().setCenter([x, y]);

        _timeout(id, () => {
            this.drawer.source(Type.Modify).removeFeature(feature);
        }, 5000);
    }

    filter(name) {
        const filter = [];
        for (const vehicle of this.vehicles) {
            if (vehicle.hasOwnProperty('x') && vehicle.hasOwnProperty('y')) {
                if (vehicle.carcode.includes(name) || vehicle.name.includes(name)) {
                    filter.push(vehicle);
                }
            }
        }
        return filter;
    }

    lock(code, name) {
        this.vehicleId = code;
        this.zoomlocked = true;
        this.toast(`${name}被锁定。`);
    }

    unlock() {
        this.drawer.source(Type.Modify).clear();
        if (this.vehicleId === null) {
            this.toast("没有车辆被锁定。");
        } else {
            this.vehicleId = null;
            this.toast("车辆锁定解除。");
        }
    }

    panel() {
        this.$$("#pannel").remove();
        const track_div = `
            <div class="page" id="pannel" style="top: 60px; width: 20vw; height: 90vh;">
                <div class="page-title">
                    <span id="vl-title">轨迹回放</span>
                    <div>
                        <div class="page-cheked">
                            <button class="button button-fill" style="background: green; cursor: pointer" 
                                id="vl-vehicle-track-back">
                                开始回放
                            </button>
                            <i class="iconfont" style="font-size: 22px; cursor: pointer;" id="panel-close">
                                &#xe6ba;
                            </i>
                        </div>
                    </div>
                </div>
                <div class="page-content"></div>
            </div>
        `;
        this.$$("#article").append(track_div);
        this.$$("#pannel").hide();

        this.$$("#vl-vehicle-track-back").on("click", () => {
            this.drawer.source(Type.Modify).clear();
            _delay('vl-vehicle-track-back', async () => {
                if (this.playbackLocked) {
                    this.$$("#vl-vehicle-track-back").css("background", "green");
                    this.$$("#vl-vehicle-track-back").html("开始回放");
                    this.playbackLocked = false;

                    // 关闭估计回放时,如果是车辆追踪模式,需要恢复车辆追踪
                    this.vehicleId = this.utils.getLocalStorage("vehicleId");

                    // 停止播放回放时清空图层
                    this.drawer.source(Type.Modify).clear();
                } else {
                    this.$$("#vl-vehicle-track-back").css("background", "red");
                    this.$$("#vl-vehicle-track-back").html("关闭回放");
                    this.playbackLocked = true;

                    // 开启轨迹回放时需要临时关闭车辆追踪
                    this.vehicleId = null;

                    // 播放回放,描画在Modify图层进行
                    await this.playback(this.playbackIndex);

                    // 关闭overlay
                    this.emitter.emit("close-overlay");
                }
            }, 300);
        });

        this.$$("#panel-close").on("click", () => {
            this.drawer.source(Type.Modify).clear();
            this.$$("#pannel").hide();
            this.clear();
        });

        this.$$("#vp-footer").remove();
        const vp_footer_div = `
            <div id="vp-footer">
                <input type="range" name="slider" min="0" max="20" step="1" value="0" id="person-slider"/>
            </div>
        `;
        this.$$("#article").append(vp_footer_div);
        this.$$("#vp-footer").hide();

        this.$$("#person-slider").on('change', () => {
            let value = this.$$("#person-slider").val();
            value = value === "0" ? 1 : parseInt(value);
            this.playbacklength = value;
        });
    }

    template() {
        const self = this;

        function popup() {
            const div = `
                <div id="ol-vehicle-popup" class="ol-popup">
                    <a href="#" id="ol-vehicle-closer" class="ol-popup-closer"></a>
                    <div class="ol-vehicle-content">
                        <div>
                            <span id="ol-vehicle-content-name">车辆:人车6号</span>|
                            <span id="ol-vehicle-content-person">驾驶员:樊晋刚</span>|
                            <span id="ol-vehicle-content-card">卡号:26910</span>
                            <button class="button button-fill color-primary" id="ol-vehicle-track">追踪</button>
                        </div>
                        <div id="ol-vehicle-pbshow">
                            <div class="item-title item-label">开始时间:
                                <div class="item-input-wrap">
                                    <input type="date" id="ol-stime">
                                </div>
                            </div>|
                            <div class="item-title item-label">结束时间:
                                <div class="item-input-wrap">
                                    <input type="date" id="ol-etime">
                                </div>
                            </div>|
                            <button class="button button-outline color-primary" id="ol-vehicle-playlist">轨迹回放</button>
                        </div>
                        <table border="1" class="table">
                            <tr><td>车辆卡号:</td><td id="ol-carcode"></td><td>车辆牌号:</td><td id="ol-carcode2"></td></tr>
                            <tr><td>入井时间:</td><td id="ol-inminetime"></td><td>当前位置:</td><td id="ol-reader"></td></tr>
                            <tr><td>运行速度:</td><td id="ol-speed"></td><td>行使里程:</td><td id="ol-mileage">0km</td></tr>
                            <tr><td>车辆水温:</td><td id="ol-wt">0℃</td><td>甲烷浓度:</td><td id="ol-ch4">0%</td></tr>
                            <tr><td>表面温度:</td><td id="ol-st">0℃</td><td>排气温度:</td><td id="ol-et">0℃</td></tr>
                            <tr><td>车辆转速:</td><td id="ol-rpm">0rpm</td><td>终端电池:</td><td id="ol-battery">0%</td></tr>
                        </table>
                    </div>
                </div>
            `;
            self.$$("#article").append(div);

            const vehicleId = self.utils.getLocalStorage("vehicleId");
            if (vehicleId !== null) {
                self.$$("#ol-vehicle-pbshow").hide();
                self.$$("#ol-vehicle-track").hide();
                self.$$("#ol-vehicle-popup").css("height", "300px");
            }
        }

        popup();
    }

    control() {
        const config = this.algo.getConfig();
        if (config === null) return;

        // 从服务器每400毫秒获取一次数据
        setInterval(() => {
            this.api.getVehicle().then(resp => {
                if (resp.code === 0) {
                    this.vehicles = resp.data.cars;
                    this.vehicle(this.vehicles);
                    this.draw();
                }
            });
        }, 1000);

        // 从自车的websocket获取数据
        const vehicleId = this.utils.getLocalStorage("vehicleId");
        if (vehicleId !== null && vehicleId !== undefined) {
            this.connect = new Socket("ws://127.0.0.1:8899");
            this.connect.create(async (data) => {
                try {
                    this.selfinfo = JSON.parse(data);

                    // 这里累加陀螺仪在x方向的角动量
                    // this.gyroscope(this.selfinfo.gyroscopeSensor[0]);
                } catch(err) {
                    console.log("[127.0.0.1:8899]数据解析异常: ", err);
                    this.selfinfo = null;
                }
            });
        }

        // 当选择器发出被选中事件
        this.emitter.on("vehicle-selected", () => {
            clearInterval(this.selectedTimer);

            const id = this.emitter.params[0]
            const vehicle = this.datas.get(id);
            this.selectedId = vehicle.carcode;

            if (CONF.NAME === "OnePiece") {
                this.emitter.emit("emit-vehicle-selected", vehicle);
            }

            this.$$("#ol-vehicle-content-name").html(`车辆: ${vehicle.name}`);
            this.$$("#ol-vehicle-content-person").html(`驾驶员: ${vehicle.driver}`);
            this.$$("#ol-vehicle-content-card").html(`卡号: ${vehicle.carcode}`);

            this.$$("#ol-carcode").html(vehicle.carcode);
            this.$$("#ol-carcode2").html(vehicle.carcode);
            this.$$("#ol-stime").val(moment().subtract(1, 'days').format("YYYY-MM-DD"));
            this.$$("#ol-etime").val(moment().add(1, 'days').format("YYYY-MM-DD"));

            this.selectedTimer = setInterval(() => {
                const vehicle = this.datas.get(id);
                this.info(vehicle);
            }, 1000);
        });

        this.emitter.on("emit-vehicle-positions", async () => {
            const readers = [];
            for (const position of this.positions.values()) {
                const reader = this.readers.get(position.node_id);
                if (reader === undefined) continue;
                readers.push(reader);
            }
            this.emitter.emit("emit-vehicle-positions-response", readers);
        });

        this.emitter.on("emit-vehicle-positions-id", async () => {
            this.positionById(this.emitter.params[0]);
        });

        this.emitter.on("emit-vehicle-filter", async () => {
            const result = this.filter(this.emitter.params[0]);
            this.emitter.emit("emit-vehicle-filter-response", result);
        });

        this.emitter.on("emit-vehicle-lock", async () => {
            const vehicle = this.emitter.params[0];
            this.lock(vehicle.carcode, vehicle.name);
        });

        this.emitter.on("emit-vehicle-unlock", async () => {
            this.unlock();
        });

        this.emitter.on("emit-vehicle-play-slider", () => {
            this.playbacklength = this.filter(this.emitter.params[0]);
        });

        this.emitter.on("emit-vehicle-playlist", async () => {
            const params = this.emitter.params[0];
            const data = await this.api.trackPlayBack(params);
            if (data.length === 0) {
                this.toast("未获取到车辆轨迹数据。");
                return;
            }

            this.playbacks = [];
            for (const item of data) {
                const id = `track-${this.utils.uuid()}`;
                const time_str = item.intime.replace('T', ' ');
                this.playbacks.push({id: id, rid: parseInt(item.rid), carid: params.carid, time: time_str});
            }

            this.emitter.emit("emit-vehicle-playlist-response", data);
        });

        this.$$("#ol-vehicle-playlist").on("click", async () => {
            await this.playlist();
        });

        this.emitter.on("emit-vehicle-playback-start", async () => {
            this.drawer.source(Type.Modify).clear();
            this.playbackIndex = this.emitter.params[0];
            this.playbackLocked = true;
            this.vehicleId = null;
            await this.playback(this.playbackIndex);
        });

        this.emitter.on("emit-vehicle-playback-stop", async () => {
            this.playbackLocked = false;
            this.vehicleId = this.utils.getLocalStorage("vehicleId");
            this.drawer.source(Type.Modify).clear();
        });

        this.$$("#ol-vehicle-track").on("click", () => {
            this.drawer.source(Type.Modify).clear();
            this.vehicleId = this.$$("#ol-carcode").html();
            this.zoomlocked = true;
        });

        this.$$("#vehicle-locked").on("click", () => {
            this.drawer.source(Type.Modify).clear();
            this.panel();
            this.$$("#vl-title").html("车辆列表");
            this.$$("#vl-vehicle-track-back").hide();
            this.$$("#pannel .page-content").empty();
            if (this.vehicles !== null) {
                const div = `<div class="block"><div class="list simple-list"><ul></ul></div></div>`;
                this.$$("#pannel .page-content").append(div);
                const length = this.vehicles.length;
                for (let i = 0; i < length; i++) {
                    // 如果没有入矿或者分站根本没有匹配,则干脆不显示
                    if (this.vehicles[i].inminetime === null || this.vehicles[i].readerid === null) {
                        continue;
                    }

                    // 如果分站无法匹配，也干脆不显示
                    const postion = this.positions.get(parseInt(this.vehicles[i].readerid));
                    if (postion === undefined) continue;

                    const id = `vehicle--${this.vehicles[i].carcode}--${this.vehicles[i].name}`;
                    const li = `
                        <li style="font-size: var(--table-row-font-size); cursor: pointer;" id=${id}>
                            <span>${this.vehicles[i].carcode} - ${this.vehicles[i].name}</span>
                        </li>
                    `;
                    this.$$("#pannel ul").append(li);
                    this.$$(`#${id}`).on("click", () => {
                        _delay('vehicle-locked', async () => {
                            const ids = id.split('--');
                            this.lock(ids[1], ids[2]);
                        }, 300);
                    });
                }
            }
            this.$$("#pannel").show();
            this.toast("点击列表选择需要被锁定的车辆。");
        });

        this.$$("#vehicle-unlocked").on("click", () => {
            this.unlock();
        });

        this.$$("#vehicle-positions").on("click", () => {
            this.panel();
            this.$$("#vl-title").html("分站列表");
            this.$$("#vl-vehicle-track-back").hide();
            this.$$("#pannel .page-content").empty();
            const div = `<div class="block"><div class="list simple-list"><ul></ul></div></div>`;
            this.$$("#pannel .page-content").append(div);
            for (const position of this.positions.values()) {
                const reader = this.readers.get(position.node_id);
                if (reader === undefined) continue;

                const id = `position-${position.node_id}`;
                const li = `
                    <li style="font-size: var(--table-row-font-size); cursor: pointer;" id=${id}>
                        <span>${position.node_id} - ${reader.regname}</span>
                    </li>
                `;
                this.$$("#pannel ul").append(li);
                this.$$(`#${id}`).on("click", () => {
                    _delay('vehicle-positions', async () => {
                        const key = parseInt(id.split('-')[1]);
                        this.positionById(key);
                    }, 300);
                });
            }
            this.$$("#pannel").show();
            this.toast("点击列表选择分站。");
        });

        this.$$("#vehicle-locked-unlocked").on("click", () => {
            if (this.lockedUnlocked) {
                this.$$("#vehicle-locked-unlocked").html("&#xe601;");
                this.vehicleId = false;
                this.lockedUnlocked = false;
            } else {
                this.$$("#vehicle-locked-unlocked").html("&#xe600;");
                this.vehicleId = this.utils.getLocalStorage("vehicleId");
                this.lockedUnlocked = true;
                this.drawer.map.getView().setZoom(12);
            }
        });
    }
}